const fs = require('fs')
const os = require('os')
const path = require('path')
const sharp = require('sharp')
const XLSX = require('xlsx')

// 配置
const config = {
	filePath: './images/',
	dist: './images-cut/',
	surplusImage: '错误文件列表.txt',
	logPath: 'logo.txt',
	index: 0,
	noFilePath: '异常的图片.txt'
}
let arrList = []
let num = 0
// 转XLSX
const toXLSX = (_data, name) => {
	try {
		console.log('------->日志输出正在生成excle:', _data.length)
		const _headers = [
			{ key: 'area', title: '台区' },
			{ key: 'user', title: '用户' },
			{ key: 'num', title: '图片数量' },
		]
		const headers = _headers.map(({ title }) => title)

			.map((v, i) => Object.assign({}, { v: v, position: String.fromCharCode(65 + i) + 1 }))

			.reduce((prev, next) => Object.assign({}, prev, {
				[next.position]: { v: next.v }
			}), {})

		const data = _data
			// 匹配 headers 的位置，生成对应的单元格数据
			.map((v, i) => _headers.map(({ key }, j) => Object.assign({}, { v: v[key], position: String.fromCharCode(65 + j) + (i + 2) })))
			// 对刚才的结果进行降维处理（二维数组变成一维数组）
			.reduce((prev, next) => prev.concat(next))
			.reduce((prev, next) => Object.assign({}, prev, {
				[next.position]: { v: next.v }
			}), {})

		// 合并 headers 和 data
		const output = Object.assign({}, headers, data)

		// 获取所有单元格的位置
		const outputPos = Object.keys(output)

		// 计算出范围
		const ref = outputPos[0] + ':' + outputPos[outputPos.length - 1]

		// 构建 workbook 对象
		const wb = {
			SheetNames: ['sheet1'],
			Sheets: {
				'sheet1': Object.assign({}, output, { '!ref': ref })
			}
		}
		// 导出 Excel
		XLSX.writeFile(wb, `${ name }.xlsx`)
		// return result.data
	} catch (e) {
		console.log('--------->xlsx处理错误', e)
	}
}
// 保存图片的方法
const savePngFile = async (file, filePath) => {
	let extname = path.extname(filePath)
	isImage = ['.jpg', '.png', '.JPG', '.PNG'].includes(extname)
	// console.log('--------->isImage', isImage)
	fs.appendFileSync(config.logPath, filePath + os.EOL, { encoding: 'utf-8' }) // 更新
	let arr = filePath.split('/')
	let area = arr[3]
	let user = arr[4]
	if (arrList.length > 0 && area !== arrList[arrList.length - 1].area) {
		arrList.push({ area: '', user: '', num: '' })
		num = 1
	}
	// 如果不是标准的图片 保存并记录
	if (!isImage) {
		// console.log('--------->不是标准的图片', filePath, extname)
		// arrList.push({ area: '', user: '', num: '' })
		let file = fs.readFileSync(filePath)
		let newPath = filePath.replace(config.filePath, config.dist) // 源地址=>新地址
		fs.writeFileSync(newPath, file)
		arrList.push({ area, user, num: 0 })
		return fs.appendFileSync(config.surplusImage, filePath + os.EOL, { encoding: 'utf-8' }) // 更新
	}
	if (arrList.length > 0 && user !== arrList[arrList.length - 1].user) {
		num = 1
		arrList.push({ area, user, num })
	} else {
		num += 1
		arrList.splice(arrList.length - 1, 1, { area, user, num })
	}
	try {
		// 剩下的都是标准的图片了 
		const image = sharp(filePath) // 当前图片
		// 获取元数据 这里可以把await 去掉 开启异步处理图片，但是性能开销可能会很大。不推荐
		await image.metadata().then((metadata) => {
			let width = metadata.width // 获取原图片宽度
			let height = metadata.height // 获取原图片高度
			if (file.indexOf('总.') !== -1) {
				filePath = filePath.replace('总.', '1总.')
				return newImage({ image, width, height, filePath })
			}
			if (file.indexOf('峰.') !== -1) {
				filePath = filePath.replace('峰.', '2峰.')
				return newImage({ image, width, height, filePath })
			}
			if (file.indexOf('谷.') !== -1) {
				filePath = filePath.replace('谷.', '3谷.')
				return newImage({ image, width, height, filePath })
			}
			if (file.indexOf('剩余金额.') !== -1) {
				filePath = filePath.replace('剩余金额.', '4金额.')
				newImage({ image, width, height, filePath })
				filePath = filePath.replace('4金额.', '5换前.')
				return newImage({ image, width, height, filePath })
			}
			if (file.indexOf('换前.') !== -1) {
				filePath = filePath.replace('换前.', '6换中.')
				return newImage({ image, width, height, filePath })
			}
			if (file.indexOf('换后.') !== -1) {
				filePath = filePath.replace('换后.', '7换后.')
				return newImage({ image, width, height, filePath })
			}
			if (file.indexOf('新电表采集模块.') !== -1) {
				filePath = filePath.replace('新电表采集模块.', '8模块.')
				return newImage({ image, width, height, filePath })
			}
			return newImage({ image, width, height, filePath })
		})
	} catch (e) {
		console.log('------->处理图片出错:', e)
		fs.appendFileSync(config.surplusImage, filePath + os.EOL, { encoding: 'utf-8' }) // 更新
		//TODO handle the exception
	}
}
const newImage = ({ image, width, height, filePath }) => {
	try {
		config.index = config.index + 1
		let newPath = filePath.replace(config.filePath, config.dist) // 源地址=>新地址
		console.log(`--------->生成新图片${ config.index }`, width, height, newPath)
		image.extract({ left: 0, top: 0, width, height }).toFile(newPath) // 生成新图片
	} catch (e) {
		//TODO handle the exception
		console.log('------->生成新图片错误e', e)
	}

}
// 清空文件夹
const delDir = async (path) => {
	let files = []
	if (fs.existsSync(path)) {
		files = fs.readdirSync(path)
		for (let file of files) {
			let curPath = path + '/' + file
			// console.log('--------->curPath', curPath)
			if (fs.statSync(curPath).isDirectory()) {
				await delDir(curPath) //递归删除文件夹
			} else {
				fs.unlinkSync(curPath) //删除文件
			}
		}
		fs.rmdirSync(path) // 删除当前文件夹
	}
}

// 解析目录
const analysisDirectory = async (path, isfirst = false) => {
	path = path ? path : config.filePath // 当前的目录路径
	// 首次执行需要清楚上一次所记录的surplusImage
	if (isfirst) {
		fs.writeFileSync(config.surplusImage, '')
		fs.writeFileSync(config.logPath, '')
		await delDir(config.dist) // 清空dist
		fs.mkdirSync(config.dist, '0755') //创建当前文件夹
		// return
	}
	const fileList = fs.readdirSync(path) // 读取目录所有文件
	// 空文件的时候也需要统添加为0的统计数据
	if (fileList.length === 0) {
		let arr = path.split('/')
		if (arr.length > 5) {
			let area = arr[3]
			let user = arr[4]
			arrList.push({ area, user, num: 0 })
		}
	}
	// 从根目录开始遍历
	for (let file of fileList) {
		let _path = `${ path }${ file }`
		let isDirectory = fs.statSync(_path).isDirectory() // 判断当前file是否为文件夹
		if (isDirectory) {
			let newDirectory = _path.replace(config.filePath, config.dist)
			fs.mkdirSync(newDirectory) // 还需要创建一个对应的cut文件夹
			_path = `${ _path }/`
			// console.log('--------->解析文件夹', _path)
			await analysisDirectory(_path)
			continue
		}
		// console.log('--------->index', _path)
		await savePngFile(file, _path) // 处理文件
	}
}
// 多加个fun 来计算一下时间 默认使用同步操作以降低性能开销和保证稳定性，如果你电脑性能强大，那么也可以在上面savePngFile() 中去掉开头的await,此时下面的时间计算无效
const init = async () => {
	let start = new Date().getTime() // 开始时间
	await analysisDirectory(null, true) // 执行解析

	await toXLSX(arrList, '查错统计') //使用业务逻辑层的方法返回值
	let end = new Date().getTime() // 结束时间
	console.log(`--------->处理完成,消耗${ ((end - start) / 1000).toFixed(2) }s`, )
}
init()
/**
 * 			佛曰:
 * 				写字楼里写字间，写字间里程序员；
 * 				程序人员写程序，又拿程序换酒钱。
 * 				酒醒只在网上坐，酒醉还来网下眠；
 * 				酒醉酒醒日复日，网上网下年复年。
 * 				但愿老死电脑间，不愿鞠躬老板前；
 * 				奔驰宝马贵者趣，公交自行程序员。
 * 				别人笑我忒疯癫，我笑自己命太贱；
 * 				不见满街漂亮妹，哪个归得程序员？
 *
 * @description 批量剪切图片 并修正电表内图片文件名
 * @tutorial 暂无参考文档
 * @param {String} paramsName = 未知的参数
 * @event 暂无事件
 * @example 暂无示例
 * @return {String} {暂无返回值}
 * @author Breathe
 */
